/*! \file COMPointer.inl
 *	\brief 
 *
 *	created:	2009/11/16
 *	created:	16:11:2009   12:42
 *	filename: 	o:\main\libs\utils\COMPointer.inl
 *	file path:	o:\main\libs\utils
 *	file base:	COMPointer
 *	file ext:	inl
 *	author:		Vitalii Trubchaninov
 *				venngraydog@gmail.com
 */

#include <algorithm>

namespace tt{
namespace utils{

template<typename COMPointerT>
COMPointer<COMPointerT>::COMPointer(COMPointerType* pCOMObject /*= NULL*/)
: m_pCOMObject(pCOMObject)
{
#ifdef TT_DEBUG
	if (m_pCOMObject)
	{
		ULONG refCount = m_pCOMObject->AddRef();
		ttAssert(refCount == 2);
		m_pCOMObject->Release();
	}
#endif //TT_DEBUG
}

template<typename COMPointerT>
COMPointer<COMPointerT>::COMPointer(const COMPointer& src)
: m_pCOMObject(src.m_pCOMObject)
{
	if (m_pCOMObject)
	{
		m_pCOMObject->AddRef();
	}
}

template<typename COMPointerT>
COMPointer<COMPointerT>::~COMPointer()
{
	if (m_pCOMObject != NULL)
	{
		m_pCOMObject->Release();
		m_pCOMObject = NULL;
	}
}

template<typename COMPointerT>
void COMPointer<COMPointerT>::reset(COMPointerType* pCOMObject = NULL)
{
	COMPointer temp(pCOMObject);
	temp.swap(*this);
}

template<typename COMPointerT>
COMPointer<COMPointerT>& COMPointer<COMPointerT>::operator=(const COMPointer& other)
{
	COMPointer temp(other);
	temp.swap(*this);
	return *this;
}

template<typename COMPointerT>
void COMPointer<COMPointerT>::swap(COMPointer& other)
{
	std::swap(m_pCOMObject, other.m_pCOMObject);
}

template <class COMPointerT>
COMPointer<COMPointerT>::operator bool() const
{
	return m_pCOMObject != NULL;
}

template<typename COMPointerT>
typename COMPointer<COMPointerT>::COMPointerType* COMPointer<COMPointerT>::get()
{
	return m_pCOMObject;
}

template<typename COMPointerT>
typename const COMPointer<COMPointerT>::COMPointerType* COMPointer<COMPointerT>::get() const
{
	return m_pCOMObject;
}

template <class COMPointerT>
typename COMPointer<COMPointerT>::COMPointerType** COMPointer<COMPointerT>::getRef()
{
	reset();
	return &m_pCOMObject;
}

template<typename COMPointerT>
typename COMPointer<COMPointerT>::COMPointerType* COMPointer<COMPointerT>::operator->()
{
	return m_pCOMObject;
}

template<typename COMPointerT>
typename const COMPointer<COMPointerT>::COMPointerType* COMPointer<COMPointerT>::operator->() const
{
	return m_pCOMObject;
}

template<typename COMPointerT>
typename COMPointer<COMPointerT>::COMPointerType& COMPointer<COMPointerT>::operator*()
{
	return *m_pCOMObject;
}

template<typename COMPointerT>
typename const COMPointer<COMPointerT>::COMPointerType& COMPointer<COMPointerT>::operator*() const
{
	return *m_pCOMObject;
}

template<typename COMPointerT>
bool COMPointer<COMPointerT>::operator==(const COMPointer<COMPointerT>& rhs) const
{
	return m_pCOMObject == rhs.m_pCOMObject;
}

template<typename COMPointerT>
bool COMPointer<COMPointerT>::operator!=(const COMPointer& rhs) const
{
	return !operator==(rhs);
}

//////////////////////////////////////////////////////////////////////////
template<typename COMPointerT>
HRESULT CoCreateInstance(REFCLSID rclsid,
						 LPUNKNOWN pUnkOuter,
						 DWORD dwClsContext,
						 REFIID riid,
						 COMPointer<COMPointerT>& ptr)
{
	COMPointerT* rawPtr = NULL;
	HRESULT hr = CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, (LPVOID*)&rawPtr);
	if (SUCCEEDED(hr))
		ptr.reset(rawPtr);
	return hr;
}

} //namespace utils
} //namespace tt
